package be.nepherte.movmanager.client.ui.components;

import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.TextBox;

/**
 * This class represents a text box in which only doubles are allowed.
 * 
 * <p>
 * This file is part of MovManager.
 * </p>
 * <p>
 * MovManager is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 * </p>
 * <p>
 * MovManager is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 * </p>
 * <p>
 * You should have received a copy of the GNU General Public License along with
 * MovManager. If not, see <a
 * href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses</a>.
 * </p>
 * 
 * @author	Bart Verhoeven
 * @version	0.1
 */
public class DoubleBox extends Composite implements HasValue<Double> {
	/**Text box holding the double.*/
	private final TextBox box = new TextBox();

	/**
	 * Creates an empty double box.
	 */
	public DoubleBox() {
		super();
		initWidget(box);
		box.addKeyPressHandler(new DoubleBoxHandler());
	}
	
	/**
	 * Creates a double box that shows the given double.
	 * 
	 * @param	d
	 * 			the double that has to be filled in this double box
	 */
	public DoubleBox(double d) {
		this();
		setValue(d);
	}

	@Override
	public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Double> handler) {
		return addHandler(handler, ValueChangeEvent.getType());
	}

	@Override
	public Double getValue() {
		String text = box.getText();
		if (text.isEmpty())
			return 0.0d;

		return Double.parseDouble(text);
	}

	@Override
	public void setValue(Double value) {
		setValue(value, false);
	}

	@Override
	public void setValue(Double value, boolean fireEvents) {
		box.setText(value == null || value == 0 ? "" : value.toString());
		
		if (fireEvents) {
			Double oldValue = getValue();
			ValueChangeEvent.fireIfNotEqual(this, oldValue, value);
		}
	}
	
	private class DoubleBoxHandler implements KeyPressHandler {
		
		/**
		 * Only double and navigational keys are processed. Other keys are
		 * canceled.
		 */
		@Override
		public void onKeyPress(KeyPressEvent event) {
			char c = event.getCharCode();
			String s = box.getText();
			
			// if no digits or navigation keys: cancel keys
			if (!(c == '0' || c == '1' || c == '2' || c == '3' || c == '4' || c == '5' || c == '6' || c == '7' || c == '8' || c == '9' || c == KeyCodes.KEY_TAB || c == KeyCodes.KEY_BACKSPACE && c == KeyCodes.KEY_LEFT || c == KeyCodes.KEY_RIGHT || c == KeyCodes.KEY_DELETE || c == KeyCodes.KEY_HOME || c == KeyCodes.KEY_END))
				box.cancelKey();
			
			// block other special characters
			if (c == '%' || c == '#' || c == '\'' || c == '$') {
				box.cancelKey();
				return;
			}
			
			// only allow '.' if it's the only '.' and not the first character
			if (c == '.' && (s.isEmpty() || s.contains("."))) {
				box.cancelKey();
				return;
			}
		}
	}
}
